#include "Camera.h"
#include "Ray.h"
#include <QtOpenGL>

Camera::Camera()
{    
    translate(Vector3f(0, 0, 1));
    rotateX(90);
    m_phi = 0.0;
}

int Camera::width()
{
    return(wid);
}

int Camera::height()
{
    return(hei);
}

void Camera::applyModelView()
{
    glRotatef(-m_phi, 1.f, 0.f, 0.f);
    glMultMatrixf(&m_invMatrix(0, 0));
}

void Camera::applyProjection(int w, int h)
{
    wid = w;
    hei = h;

    GLdouble  largura =  (GLdouble) w;
    GLdouble  altura  =  (GLdouble) h;


    gluPerspective(70, largura/altura, 0.1, 2000);
}

void Camera::goAhead(float d)
{
    translate(Vector3f(0, 0, -1) * d);
}

void Camera::goBack(float d)
{
    translate(Vector3f(0, 0, 1) * d);
}

void Camera::goUp(float d)
{
    translate(Vector3f(0, 1, 0) * d);
}

void Camera::goDown(float d)
{
    translate(Vector3f(0, -1, 0) * d);
}

void Camera::goLeft(float d)
{
    translate(Vector3f(-1, 0, 0) * d);
}

void Camera::goRight(float d)
{
    translate(Vector3f(1, 0, 0) * d);
}

void Camera::turnRight(float d)
{
    rotateY(-d);
}

void Camera::turnLeft(float d)
{
    rotateY(d);
}


void Camera::turnUp(float d)
{
    if(m_phi + d > 70)
    {
        m_phi = 70;
        return;
    }

    m_phi += d;
}

void Camera::turnDown(float d)
{
    if(m_phi - d < -70)
    {
        m_phi = -70;
        return;
    }

    m_phi -= d;
}


Ray Camera::traceRay(int i, int j)
{
     //Pixel to Point3f - inicio

     float id = (float) i;
     float jd = (float) j;

     GLint    viewport[4];
     GLdouble modelview[16];
     GLdouble projection[16];
     GLdouble posX, posY, posZ;

     glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
     glGetDoublev(GL_PROJECTION_MATRIX, projection);
     glGetIntegerv(GL_VIEWPORT, viewport);

     gluUnProject(jd, viewport[3] - id, 0.0, modelview, projection, viewport, &posX, &posY, &posZ);

     //Pixel to Point3f - fim

     Point3f  destino(posX, posY, posZ);
     Point3f  origem(m_matrix(0, 3), m_matrix(1, 3), m_matrix(2, 3));
     Vector3f direcao(destino - origem);
     Ray      raio(origem, direcao.normalized());

     return raio;
}

void Camera::translate(const Vector3f &vec)
{
    m_matrix = m_matrix * Transform().translate(vec).matrix();
    m_invMatrix = Transform().translate(vec).invMatrix() *  m_invMatrix;
}

void Camera::rotateX(float ang)
{
    m_matrix = m_matrix * Transform().rotateX(ang).matrix();
    m_invMatrix = Transform().rotateX(ang).invMatrix() *  m_invMatrix;
}

void Camera::rotateY(float ang)
{
    m_matrix = m_matrix * Transform().rotateY(ang).matrix();
    m_invMatrix = Transform().rotateY(ang).invMatrix() *  m_invMatrix;
}

